/*
 * @Author: hanxin 
 * @Date: 2021-08-12 17:24:38 
 * @Last Modified by: hanxin
 * @Last Modified time: 2021-08-15 22:45:00
 * 验证客户端链接类
 */
package ServerService;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import java.util.Hashtable;
import java.util.Properties;

import common.Message;
import common.MessageType;
import common.user;

public class connectSer {
    private ServerSocket serverSocket = null;

    // 用hashtable来暂时替代数据库缓存存放用户信息
    private static Hashtable<String, user> validUser = new Hashtable<>();
    // properties永久存放用户信息
    private static Properties properties = new Properties();

    public static Hashtable<String, user> getValidUser() {
        return validUser;

    }

    public static Properties getProperties() {
        return properties;
    }

    // 设置静态代码块暂时存放合法测试用户
    static {
        // 将用户id设置为key值
        validUser.put("hanxin", new user("hanxin", "123123"));
        validUser.put("jack", new user("jack", "123123"));
        validUser.put("瀚文", new user("瀚文", "123123"));
        //每次运行时将用户信息写入内存hashtable
        registerSer.writeDB();
    }

    /**
     * 从hash表中取出对象是否为空,判断当前用户是否存在
     * 
     * @param uid
     * @param passwd
     * @return
     */
    public boolean checkUserVaild(String uid, String passwd) {
        user u = validUser.get(uid);
        if (u == null) {
            return false;
        }

        if (!u.getPasswd().equals(passwd)) {
            return false;
        }
        return true;
    }

    public connectSer() {
        // 注意序列化时的包结构问题,客户端与服务端之间传输的序列化的类的对象包结构必须一致.
        try {

            serverSocket = new ServerSocket(11122);

            System.out.println("服务端在" + serverSocket.getLocalPort() + "端口监听");
            // 在监听端口时启动服务器推送消息线程
            serverSendMessagetoAll ssma = new serverSendMessagetoAll();
            ssma.start();
            //启动注册服务线程
            registerSer res = new registerSer();
            res.start();
            while (true) {
                // 循环监听客户端链接,没有客户端连接将阻塞在此位置
                Socket socket = serverSocket.accept();

                // 接收客户端信息
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

                // 反序列化客户端user对象准备验证
                Object obj = ois.readObject();
                user u = (user) obj;

                // 序列化message对象返回给客户端
                Message mess = new Message();// 定义message对象准备返回

                // test_user_login
                if (checkUserVaild(u.getUser(), u.getPasswd())) {

                    mess.setMessType(MessageType.MESSAGE_LOGIN_SUCCESS);
                    oos.writeObject(mess);
                    // socket.shutdownOutput();

                    serverConnectClientThread scct = new serverConnectClientThread(socket, u.getUser());
                    scct.start();
                    // 新建的socket线程放入集合
                    manageClientThreads.Threadjoin(u.getUser(), scct);

                    // 上线就接收离线消息
                    offline_Message_send(u);
                } else {
                    System.out.println("用户:" + u.getUser() + " 登录失败");

                    mess.setMessType(MessageType.MESSAGE_LOGIN_FAIL);
                    oos.writeObject(mess);
                    // socket.shutdownOutput();

                    socket.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 如果while循环退出服务端就不需要再继续监听端口,服务端退出
            try {
                serverSocket.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 离线消息发送方法,离线用户一上线立刻发送
     * 
     * @param u
     */
    public void offline_Message_send(user u) {
        try {
            ArrayList<Message> messList = offline_Message_Save.takeMessage(u.getUser());
            // 若返回的离线消息列表不为空,即该用户确实存在离线消息
            if (messList != null) {

                for (Message message : messList) {
                    // 如果要向客户端循环发送消息(java默认序列化),socket.getOutputStream最好每次写完都重新获取。
                    // 否则可能会出现java.io.StreamCorruptedException: invalid stream header: 7371007E 异常
                    // 序列化的头文件不合法
                    ObjectOutputStream oos = new ObjectOutputStream(
                            manageClientThreads.returnthread(u.getUser()).socket.getOutputStream());
                    oos.writeObject(message);
                }
                messList.clear();// 用户上线发送完全部离线消息,清除集合中的数据
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
